home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Graphics Samples / Test Cubics (cubic to quad) ƒ / TestCubics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-21  |  19.9 KB  |  984 lines  |  [TEXT/MPS ]

  1. /**\
  2. |**| =====================================================================
  3. |**|
  4. |**|    FILENAME
  5. |**|        TestCubics.c
  6. |**|    
  7. |**|    DESCRIPTION
  8. |**|        This program demonstrates Cubic splines in Quickdraw GX.
  9. |**|    
  10. |**|    COPYRIGHT
  11. |**|        ©1992-1996 Copyright Apple Computer, Inc.
  12. |**|        All rights reserved.
  13. |**|    
  14. |**|    Change History:
  15. |**|
  16. |**|        4/96    cnn        Changed fixed to Fixed. Updated the header
  17. |**|                    filename, description, and copyright.
  18. |**|                    Added name for parameter cursFlag in DoContentClick.
  19. |**|                    Changed (temppoint != where) to
  20. |**|                    ((temppoint.x != where->x) || (temppoint.y != where->y)).
  21. |**|                    Changed tempstring from a Str255 to a char array.
  22. |**|                    Added definition of "qd" with #if conditional.
  23. |**|                    Changed mClip to mPoints. Removed non-functional
  24. |**|                    "Open..." and "Save As..." menu items from File menu.
  25. |**|
  26. |**| =====================================================================
  27. \**/
  28.  
  29. #include "TestCubics.h"
  30. #include <Strings.h>
  31.  
  32. Cursor gHandCurs;
  33. Boolean gPolyMode;
  34. short        gFileRef;
  35. long        gcount = 0;
  36. long        gticks = 0;
  37.  
  38. long        gpointcount = 0;
  39. long        gquadcount = 0;
  40.  
  41. long        geindx = 2;
  42. extended    gerror = 0.25;
  43.  
  44. short        gcurrent = 0;
  45.  
  46. gxGraphicsClient gClient;
  47.  
  48. #if GENERATINGCFM
  49.     QDGlobals        qd;
  50. #else
  51.     #ifndef SYMANTEC_C
  52.         #ifndef SYMANTEC_CPLUS
  53.         #define __MPW_ONLY__
  54.         #endif
  55.     #endif
  56.     
  57.     #if defined (__SC__) && defined (__MPW_ONLY__)
  58.     QDGlobals        qd;
  59.     #endif
  60.     
  61.     #undef __MPW_ONLY__
  62. #endif
  63.  
  64. #pragma segment Main
  65. void main(void)
  66. {
  67.     Initialize();
  68.     EventLoop();
  69. }
  70.  
  71. #pragma segment Main
  72. void EventLoop(void)
  73. {
  74.     Boolean            gotEvent;
  75.     EventRecord     event;
  76.     short            cursFlag;
  77.  
  78.     cursFlag = kCursInit;
  79.     
  80.     do
  81.         {
  82.             SystemTask();
  83.             gotEvent = GetNextEvent(everyEvent,&event);
  84.                 
  85.             if(gotEvent)
  86.                 {
  87.                     AdjustCursor(&event,&cursFlag);
  88.                     DoEvent(&event,&cursFlag);
  89.                 }
  90.             else
  91.                 {
  92.                     AdjustCursor(&event,&cursFlag);
  93.                     /* do Idle stuff */
  94.                 }
  95.         }while(true);
  96. }
  97.  
  98. #pragma segment Main
  99. void DoEvent(EventRecord *event,
  100.                          short *cursFlag)
  101. {
  102.     short         part;
  103.     WindowPtr     window;
  104.     char         key;
  105.     
  106.     switch(event->what)
  107.         {
  108.             case nullEvent:
  109.                 AdjustCursor(event,cursFlag);
  110.                 break;
  111.                 
  112.             case mouseDown:
  113.                 part = FindWindow(event->where,&window);
  114.                 
  115.                 switch(part)
  116.                     {
  117.                         case inMenuBar:
  118.                             AdjustMenus();
  119.                             DoMenuCommand(MenuSelect(event->where));
  120.                             break;
  121.                         
  122.                         case inSysWindow:
  123.                             SystemClick(event,window);
  124.                             break;
  125.                         
  126.                         case inContent:
  127.                             if(window!=FrontWindow())
  128.                                 SelectWindow(window);
  129.                             else
  130.                                 DoContentClick(window,event,cursFlag);
  131.                             break;
  132.                             
  133.                         case inDrag:
  134.                             DragWindow(window,event->where,&qd.screenBits.bounds);
  135.                             break;
  136.                         
  137.                         case inGoAway:
  138.                             if(TrackGoAway(window,event->where))
  139.                                 DoCloseWindow(window);        //  Quit
  140.                             break;
  141.                             
  142.                         case inGrow:
  143.                             DoGrowWindow(window,event);
  144.                             break;
  145.                         
  146.                         case inZoomIn:
  147.                         case inZoomOut:
  148.                             if(TrackBox(window,event->where,part))
  149.                                 DoZoomWindow(window,part);
  150.                             break;
  151.                     }
  152.                 break;
  153.             
  154.             case keyDown:
  155.                 key = event->message & charCodeMask;
  156.                 if(event->modifiers & cmdKey)
  157.                     {
  158.                         AdjustMenus();
  159.                         DoMenuCommand(MenuKey(key));
  160.                     }
  161.                 break;
  162.                 
  163.             case activateEvt:
  164.                 break;
  165.             
  166.             case updateEvt:
  167.                 DoUpdate((WindowPtr) event->message);
  168.                 break;
  169.             
  170.         }
  171. }
  172.  
  173. #pragma segment Main
  174. void AdjustCursor(EventRecord *event,
  175.                                     short *cursFlag)
  176. {
  177.     WindowPtr    window;
  178.     RgnHandle contRgn;
  179.     RgnHandle growRgn;
  180.     Rect            growRect;
  181.     
  182.     window = FrontWindow();
  183.     if(!IsDAWindow(window))
  184.         {
  185.             contRgn = NewRgn();
  186.             growRgn = NewRgn();
  187.             
  188.             if(IsAppWindow(window))
  189.                 {
  190.                     CopyRgn(((WindowPeek)window)->contRgn,contRgn);
  191.                     
  192.                     growRect = (*((WindowPeek)window)->contRgn)->rgnBBox;
  193.                     growRect.top = growRect.bottom - kGrowBHeight;
  194.                     growRect.left = growRect.right - kGrowBWidth;
  195.                     
  196.                     SetPort(window);
  197.                     
  198.                     RectRgn(growRgn,&growRect);
  199.                     
  200.                     SetOrigin(-window->portBits.bounds.left,
  201.                                         -window->portBits.bounds.top);
  202.                     
  203.                     DiffRgn(contRgn,growRgn,contRgn);
  204.                     SetOrigin(0,0);
  205.                 }
  206.                                 
  207.                 if(PtInRgn(event->where,contRgn))
  208.                     {
  209.                         if(event->modifiers & optionKey)
  210.                             {
  211.                                 // do the hand
  212.                                 if(*cursFlag != kCursHand)
  213.                                     {
  214.                                         SetCursor(&gHandCurs);
  215.                                         *cursFlag = kCursHand;
  216.                                     }
  217.                             }
  218.                         else
  219.                             {
  220.                                 if(*cursFlag != kCursCross)
  221.                                     {
  222.                                         SetCursor(*GetCursor(crossCursor));
  223.                                         *cursFlag = kCursCross;
  224.                                     }
  225.                             }
  226.                     }
  227.                 else
  228.                     {
  229.                         SetCursor(&qd.arrow);
  230.                         *cursFlag = kCursArrow;
  231.                     }
  232.                 DisposeRgn(growRgn);
  233.                 DisposeRgn(contRgn);
  234.         }
  235.     else
  236.         {
  237.             if(*cursFlag != kCursArrow)
  238.                 {
  239.                     SetCursor(&qd.arrow);
  240.                     *cursFlag = kCursArrow;
  241.                 }
  242.         }
  243. }
  244. #pragma segment Main
  245. void DoGrowWindow(WindowPtr window,
  246.                                     EventRecord *event)
  247. {
  248.     long        growResult;
  249.     Rect        tempRect;
  250.     DocumentPeek doc;
  251.     
  252.     tempRect = qd.screenBits.bounds;
  253.     tempRect.left = kMinDocSize;
  254.     tempRect.top = kMinDocSize;
  255.     
  256.     growResult = GrowWindow(window, event->where, &tempRect);
  257.  
  258.     if (growResult!=0) 
  259.         {
  260.             doc = (DocumentPeek) window;
  261.             SizeWindow(window, LoWrd(growResult), HiWrd(growResult), true);
  262.             ResizeWindow(window);
  263.     }
  264. }
  265. #pragma segment Main
  266. void DoZoomWindow(WindowPtr window,
  267.                                     short part)
  268. {
  269.     ZoomWindow(window, part, window == FrontWindow());
  270.     ResizeWindow(window);
  271. }
  272.  
  273. #pragma segment Main
  274. void ResizeWindow(WindowPtr window)
  275. {
  276.     InvalRect(&window->portRect);
  277. }
  278.  
  279. #pragma segment Main
  280. void DoUpdate(WindowPtr    window)
  281. {
  282.     if (IsAppWindow(window)) 
  283.         {
  284.             BeginUpdate(window);
  285.             if (! EmptyRgn(window->visRgn))
  286.                 DrawWindow(window);
  287.             EndUpdate(window);
  288.         }
  289. }
  290.  
  291. #pragma segment Main
  292. void DoContentClick(WindowPtr      window,
  293.                     EventRecord *event,
  294.                     short        *cursFlag)
  295. {
  296.     DocumentPeek     doc;
  297.  
  298.     Point        orgPoint;
  299.  
  300.     long        pinVal;
  301.     Rect        pinRect;
  302.     Rect        limitRect;
  303.     
  304.     long        indx;
  305.     
  306.     SetWorkRect(window,&pinRect,&limitRect);
  307.     
  308.     orgPoint = event->where;
  309.     GlobalToLocal(&orgPoint);        // now in local coordinates
  310.         
  311.     pinVal = PinRect(&pinRect,orgPoint);
  312.     orgPoint.h = LoWrd(pinVal);
  313.     orgPoint.v = HiWrd(pinVal);
  314.     
  315.     // convert the gxPoint to fixed gxPoint units and check to see if it
  316.     // is hitting any of the handles off the cubic and re-draw them
  317.     
  318.     doc = (DocumentPeek) window;
  319.     
  320.     // check to see if we have clicked on one of the control points
  321.  
  322.     {
  323.         gxPoint     *dataPtr;
  324.         
  325.         Boolean            found = false;
  326.     
  327.         gcurrent = (-1);            // this is to know if we clicked on nothing
  328.     
  329.         HLockHi((Handle) doc->data );
  330.     
  331.         dataPtr =(gxPoint *) *doc->data;
  332.         
  333.         for( indx = 0; indx < gpointcount; ++indx )
  334.             {                        
  335.                 gcurrent = indx;
  336.  
  337.                 if( DoCubicDrag( dataPtr, orgPoint, doc ) )
  338.                     {            
  339.                         found = true;
  340.                         break;
  341.                     }                
  342.             }
  343.     
  344.         HUnlock((Handle) doc->data );
  345.  
  346.         if( found == false )
  347.             {
  348.                 Handle        dataHdl = (Handle) doc->data;
  349.                                 
  350.                 // ## for now we just add one gxPoint
  351.                 
  352.                 SetHandleSize( dataHdl, ( doc->count + 1 ) * sizeof( gxPoint ) );
  353.                 
  354.                 if( MemError() != noErr ) goto FailedToAddPoint;
  355.                 // now store the gxPoint
  356.                 
  357.                 {
  358.                     gxPoint *dataPtr = & (*(gxPoint **)dataHdl)[ doc->count ];
  359.                     
  360.                     dataPtr->x = ff( orgPoint.h );
  361.                     dataPtr->y = ff( orgPoint.v );
  362.                     
  363.                     DrawControlHandle( dataPtr );
  364.                 }
  365.                 
  366.                 // increase the count
  367.                 
  368.                 doc->count += 1;
  369.                 gpointcount = doc->count;
  370.                 gcurrent = ( ( gpointcount - 1 ) / 3 ) * 3;
  371.  
  372.                 DrawCubicNumbers( doc );
  373.                 
  374.                 // if this makes an entirely new cubic then draw the gxCurve
  375.                 
  376.                 if( ( doc->count == 4 ) || ( ( 4 < doc->count ) && ( ( doc->count - 4 ) % 3 ) == 0 ) )
  377.                     DrawCurves( doc->data );
  378.             }
  379.     }    
  380.  
  381. FailedToAddPoint:;
  382.  
  383. }
  384.     
  385. #pragma segment Main
  386.  
  387. short DoCubicDrag( gxPoint *dataPtr, Point    start, DocumentPeek doc )
  388. {
  389.     gxRectangle        box;
  390.     
  391.     gxPoint        *where;
  392.     
  393.     where = & dataPtr[ gcurrent ];
  394.         
  395.     // first check to see if the start gxPoint is near the handle
  396.     
  397.     box.left = ff( start.h - 2 );
  398.     box.top = ff( start.v - 2 );
  399.     box.right = ff( start.h + 2 );
  400.     box.bottom = ff( start.v + 2 );
  401.     
  402.     if( GXTouchesRectanglePoint( &box, where ) != false )
  403.         {
  404.             gxShape        sh;
  405.             gxShape        sh2;
  406.  
  407.             gxColor        tempcolor;
  408.             gxColor        tempcolor2;
  409.             
  410.             long        cubeindx;
  411.             
  412.             cubeindx = gcurrent & ~0x3;
  413.             
  414.             if( gcurrent <= 0 )
  415.                 cubeindx = 0;
  416.             else
  417.                 cubeindx = ( ( gcurrent - 1 ) / 3 ) * 3;
  418.             
  419.             if( gpointcount < ( cubeindx + 3 ) ) return( false );
  420.             
  421.             tempcolor.space = gxGraySpace;
  422.             tempcolor.element.gray = 0;
  423.             tempcolor.profile = nil;
  424.         
  425.             tempcolor2.space = gxGraySpace;
  426.             tempcolor2.element.gray = 0xFFFF;
  427.             tempcolor2.profile = nil;
  428.         
  429.             EraseRect(& ((WindowPtr)doc)->portRect );
  430.             sh = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh, gxOpenFrameFill );
  431.             GXDrawShape( sh );
  432.             GXDisposeShape( sh );
  433.  
  434.             do
  435.                 {                    
  436.                     gxPoint        temppoint;
  437.                     gxPoint        savepoint;
  438.                     
  439.                     GXGetViewPortMouse( doc->vp, &temppoint );
  440.                     
  441.                     GXIgnoreGraphicsNotice( color_already_set );
  442.                     GXIgnoreGraphicsNotice( halftone_already_set );
  443.                     
  444.                     if( (temppoint.x != where->x) || (temppoint.y != where->y) )
  445.                         {
  446.                             savepoint = *where;
  447.                             
  448.                             *where = temppoint;
  449.                             
  450.                             // draw the new  cubic in xor mode
  451.                             
  452.                             sh = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh, gxOpenFrameFill );
  453.                             
  454.                             SetShapeFastXorTransfer( sh, &tempcolor2, &tempcolor );
  455.                             
  456.                             // erase the previous cubic by drawing in xor mode
  457.                             
  458.                             *where = savepoint;
  459.                             
  460.                             sh2 = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh2, gxOpenFrameFill );
  461.                             SetShapeFastXorTransfer( sh2, &tempcolor, &tempcolor2 );
  462.                             
  463.                             GXDrawShape( sh );            // erase first
  464.                             GXDrawShape( sh2 );            // draw now
  465.  
  466.                             GXDisposeShape( sh );
  467.                             GXDisposeShape( sh2 );
  468.                             
  469.                             *where = temppoint;
  470.                             
  471.                             DrawCubicNumbers( doc );
  472.                         }
  473.                     
  474.                     GXPopGraphicsNotice();
  475.                     GXPopGraphicsNotice();
  476.                                     
  477.                 } while( StillDown() );
  478.  
  479.             InvalRect(& ((WindowPtr)doc)->portRect );
  480.             
  481.             return( true );
  482.         }
  483.     else
  484.         {
  485.             return( false );
  486.         }
  487. }
  488.  
  489. #pragma segment Main
  490. void SetWorkRect(WindowPtr window,
  491.                                  Rect            *pinRect,
  492.                                  Rect            *limitRect)
  493. {
  494.     SetPort(window);
  495.     *limitRect = (*((WindowPeek) window)->contRgn)->rgnBBox;
  496.     GlobalToLocal(&TopLeft(*limitRect));
  497.     GlobalToLocal(&BotRight(*limitRect));
  498.     
  499.     *pinRect = *limitRect;
  500.     
  501.     InsetRect(limitRect,-5,-5);
  502.     InsetRect(pinRect,5,5);
  503.     return;
  504. }
  505. #pragma segment Main
  506. void Initialize( void )
  507. {
  508.     Handle                menuBar;
  509.     Ptr                        storage;
  510.     WindowPtr            window;
  511.     DocumentPeek     doc;
  512.     CursHandle        hCurs;
  513.  
  514.     MaxApplZone(); 
  515.     MoreMasters(); MoreMasters(); MoreMasters();
  516.  
  517.     gClient = GXNewGraphicsClient(nil, 800L * 1024L, 0);
  518.     GXEnterGraphics();
  519.  
  520.     SetGraphicsLibraryErrors();
  521.     SetGraphicsLibraryNotices();
  522.  
  523.     InitGraf((Ptr) &qd.thePort);
  524.     InitFonts();
  525.     InitWindows();
  526.     InitMenus();
  527.     TEInit();
  528.     InitDialogs(nil);
  529.     InitCursor();
  530.  
  531.     menuBar = GetNewMBar(rMenuBar);
  532.  
  533.     SetMenuBar(menuBar);
  534.     DisposHandle(menuBar);
  535.     AddResMenu(GetMHandle(mApple), 'DRVR');
  536.     DrawMenuBar();
  537.  
  538.     storage = NewPtr(sizeof( DocumentRecord ));
  539.     
  540.     if ( storage != nil ) 
  541.         {                        
  542.             window = GetNewWindow(rDocWindow, storage, (WindowPtr) -1);
  543.  
  544.             doc = (DocumentPeek) window;
  545.             doc->vp = GXNewWindowViewPort( window );
  546.             
  547.             GXIgnoreGraphicsNotice(transform_already_set);
  548.             SetDefaultViewPort( doc->vp );
  549.             GXPopGraphicsNotice();
  550.             
  551.             // gxInitialize all of the fields that have to do with the document
  552.             
  553.             doc->count = 0;
  554.             doc->data = (gxPoint **) NewHandle( 0 );        // there are no points
  555.             
  556.             ShowWindow(window);
  557.         }
  558.      else
  559.         DisposPtr(storage);            /* get rid of the storage if it is never used */
  560.         
  561.     hCurs = (CursHandle) GetResource('CURS',rHandCurs);
  562.     
  563.     if(hCurs != nil)
  564.         {
  565.             gHandCurs = **hCurs;
  566.             ReleaseResource((Handle) hCurs);
  567.         }
  568.     
  569.     gPolyMode = false;
  570. }
  571. #pragma segment Main
  572. void DrawControlHandle( gxPoint *where )
  573. {
  574.     gxRectangle        box;
  575.     gxShape             sh;
  576.     
  577.     box.left = where->x - ff( 2 );
  578.     box.top = where->y - ff( 2 );
  579.     box.right = where->x + ff( 2 );
  580.     box.bottom = where->y + ff( 2 );
  581.     
  582.     sh = GXNewRectangle( &box );
  583.  
  584.     GXDrawShape( sh );
  585.     GXDisposeShape( sh );
  586. }
  587.  
  588. void DrawCubicNumbers( DocumentPeek doc )
  589. {
  590.  
  591.     char    tempstring [256];
  592.     
  593.     Rect    erasebox = { 0, 0, 26, 170 };
  594.             
  595.     TextFont( geneva );
  596.     TextSize( 9 );
  597.     
  598.     // now calculate the number of quadratics that are needed to approximate this cubic
  599.     
  600.     sprintf( tempstring, "ticks: %d count: %d", gticks, gpointcount );
  601.     
  602.     EraseRect( &erasebox );
  603.     MoveTo( 5, 24 );
  604.     DrawString( c2pstr( tempstring ) );
  605.     
  606.     // we also need to calculate the error for the current cubic
  607.     
  608.     {
  609.         long             cubeindx;
  610.         extended     ax, ay, a, n;
  611.         extended     curveerror;
  612.         
  613.         long            count;
  614.         gxPoint            *dataPtr; 
  615.         
  616.         if( gcurrent <= 0 ) 
  617.             cubeindx = 0;
  618.         else
  619.             cubeindx = ( ( gcurrent - 1 ) / 3 ) * 3;
  620.         
  621.         if( gpointcount < ( cubeindx + 4 ) ) goto NotDoneYet;
  622.         
  623.         dataPtr = *(doc->data);
  624.         dataPtr = & dataPtr[ cubeindx ];
  625.         
  626.         ax = Fix2X( ( dataPtr[ 3 ].x - dataPtr[ 0 ].x ) + 3 * ( dataPtr[ 1 ].x - dataPtr[ 2 ].x ) );
  627.         ay = Fix2X( ( dataPtr[ 3 ].y - dataPtr[ 0 ].y ) + 3 * ( dataPtr[ 1 ].y - dataPtr[ 2 ].y ) );
  628.         
  629.         a = hypot( ax, ay );
  630.         
  631.         n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
  632.         count = ceil( n );
  633.         
  634.         curveerror = a / ( 20 * count * count * count );
  635.         
  636.         sprintf( tempstring, "error: %.4lf  quads: %d", curveerror, count );
  637.         MoveTo( 5, 12 );
  638.         DrawString( c2pstr( tempstring ) );
  639.     }
  640. NotDoneYet:;
  641. }
  642.  
  643. void DrawCubicControl( gxShape sh )                // given a cubic it shows where the control points are
  644. {
  645.     short    count;
  646.     short    indx;
  647.     
  648.     Fixed        cross[ 11 ];
  649.     gxPoint        where;
  650.     
  651.     gxShape    sh2;
  652.     
  653.     if( GXCountShapeContours( sh ) == 1 )
  654.         {            
  655.             count = GXCountShapePoints( sh, 1 ) - 2;
  656.             
  657.             cross[ 0 ] = 2;
  658.             cross[ 1 ] = 2;
  659.             cross[ 6 ] = 2;
  660.             
  661.             for( indx = 1; 0 < count; --count )
  662.                 {
  663.                     GetShapeIndexPoint( sh, ++indx, &where );
  664.                 
  665.                     cross[ 2 ] = where.x - ff( 3 );
  666.                     cross[ 3 ] = where.y - ff( 3 );
  667.                     cross[ 4 ] = where.x + ff( 3 );
  668.                     cross[ 5 ] = where.y + ff( 3 );
  669.                     cross[ 7 ] = where.x + ff( 3 );
  670.                     cross[ 8 ] = where.y - ff( 3 );
  671.                     cross[ 9 ] = where.x - ff( 3 );
  672.                     cross[ 10 ] = where.y + ff( 3 );
  673.                     
  674.                     sh2 = GXNewPolygons((gxPolygons *) & cross[ 0 ] );
  675.                     GXSetShapeFill( sh2, gxOpenFrameFill );
  676.                     GXDrawShape( sh2 );
  677.                     GXDisposeShape( sh2 );
  678.                 }
  679.         }
  680. }
  681.  
  682. #pragma segment Main
  683. void DrawWindow(WindowPtr window)
  684. {
  685.     DocumentPeek doc;
  686.     PenState    pen;
  687.     
  688.     doc = (DocumentPeek) window;
  689.     
  690.     SetPort(window);
  691.     GetPenState(&pen);
  692.     
  693.     PenNormal();
  694.     EraseRect(&window->portRect);
  695.     
  696.     gticks = TickCount();
  697.     
  698.     DrawCurves( doc->data );
  699.     gticks = TickCount() - gticks;
  700.     
  701.     DrawCubicNumbers( doc );
  702.  
  703.     // we now draw the cubic and its control points
  704.     
  705.     ForeColor(blackColor);
  706.     DrawMyGrow(window);
  707.     
  708.     SetPenState(&pen);
  709.     return;
  710. }
  711.  
  712. void DrawCurves( gxPoint **data )
  713. {
  714.     long         indx;
  715.     gxColor        tempcolor;
  716.     gxShape        sh;
  717.  
  718.     gxPoint        *dataPtr;
  719.  
  720.     tempcolor.space = gxRGBSpace;
  721.     tempcolor.profile = nil;
  722.     tempcolor.element.rgb.red = 0xFFFF;
  723.     tempcolor.element.rgb.green = tempcolor.element.rgb.blue = 0;
  724.  
  725.     HLock((Handle) data );
  726.  
  727.     dataPtr = *data;
  728.  
  729.     for( indx = 4; indx <= gpointcount; indx += 3 )
  730.         {
  731.             cubic *cube = (cubic *) & dataPtr[ indx - 4 ];
  732.             
  733.             sh = NewCubic( cube );     // first draw the reference cubic (in red)
  734.             GXSetShapeFill( sh, gxOpenFrameFill );
  735.             GXSetShapeColor( sh, &tempcolor );
  736.             GXDrawShape( sh );
  737.             GXDisposeShape( sh );
  738.             
  739.             sh = NewCubic2( cube, gcount );  GXSetShapeFill( sh, gxOpenFrameFill );
  740.         
  741.             GXDrawShape( sh );
  742.             DrawCubicControl( sh );
  743.             GXDisposeShape( sh );
  744.  
  745.             DrawControlHandle( &cube->a );
  746.             DrawControlHandle( &cube->b );
  747.             DrawControlHandle( &cube->c );
  748.             DrawControlHandle( &cube->d );
  749.         }
  750.         
  751.     HUnlock((Handle) data );
  752. }
  753.  
  754. #pragma segment Main
  755. void DrawMyGrow(WindowPtr window)
  756. {
  757.     Rect tempRect;
  758.     Rect drawRect;
  759.     PenState pen;
  760.     
  761.     SetPort(window);
  762.     GetPenState(&pen);
  763.     PenNormal();
  764.     
  765.     tempRect = (*((WindowPeek) window)->contRgn)->rgnBBox;
  766.     
  767.     drawRect.top = tempRect.bottom - 16;
  768.     drawRect.left = tempRect.right -16;
  769.     drawRect.bottom = tempRect.bottom;
  770.     drawRect.right = tempRect.right;
  771.     
  772.     GlobalToLocal(&TopLeft(drawRect));
  773.     GlobalToLocal(&BotRight(drawRect));
  774.     
  775.     EraseRect(&drawRect);
  776.     FrameRect(&drawRect);
  777.     
  778.     drawRect.right -= 2;
  779.     drawRect.bottom -= 2;
  780.     drawRect.left += 5;
  781.     drawRect.top += 5;
  782.     
  783.     FrameRect(&drawRect);
  784.     
  785.     drawRect.right -= 4;
  786.     drawRect.bottom -= 4;
  787.     drawRect.top -= 2;
  788.     drawRect.left -= 2;
  789.     
  790.     EraseRect(&drawRect);
  791.     FrameRect(&drawRect);
  792.     
  793.     SetPenState(&pen);
  794.     return;
  795. }
  796.  
  797.  
  798. #pragma segment Main
  799. void AdjustMenus( void )
  800. {
  801.     WindowPtr    window;
  802.     MenuHandle    menu;
  803.     Boolean        undo;
  804.  
  805.     window = FrontWindow();
  806.  
  807.     menu = GetMHandle(mEdit);
  808.     undo = false;
  809.     
  810.     if ( IsDAWindow(window) ) 
  811.         undo = true;
  812.     
  813.     if ( undo )
  814.         {
  815.             EnableItem(menu, iUndo);
  816.             EnableItem(menu, iCut);
  817.             EnableItem(menu, iCopy);
  818.             EnableItem(menu, iPaste);
  819.             EnableItem(menu, iClear);
  820.         }
  821.     else 
  822.         {
  823.             DisableItem(menu, iUndo);
  824.             DisableItem(menu, iCut);
  825.             DisableItem(menu, iCopy);
  826.             DisableItem(menu, iPaste);
  827.             DisableItem(menu, iClear);
  828.         }
  829.         
  830.     return;
  831. }
  832.  
  833. #pragma segment Main
  834. void DoMenuCommand(long menuResult)
  835. {
  836.     short        menuID;             /* the resource ID of the selected menu */
  837.     short        menuItem;           /* the item number of the selected menu */
  838.     short        itemHit;
  839.     Str255        daName;
  840.     short        daRefNum;
  841.     WindowPtr    window;
  842.     
  843.     window = FrontWindow();
  844.     
  845.     menuID = HiWrd(menuResult);    /* use macros for efficiency to... */
  846.     menuItem = LoWrd(menuResult);    /* get menu item number and menu number */
  847.     
  848.     switch ( menuID ) 
  849.         {
  850.             case mApple:
  851.                 switch ( menuItem ) 
  852.                     {
  853.                         case iAbout:
  854.                             itemHit = Alert(rAboutAlert, nil);
  855.                             break;
  856.                         default:
  857.                             GetItem(GetMHandle(mApple), menuItem, daName);
  858.                             daRefNum = OpenDeskAcc(daName);
  859.                             break;
  860.                     }
  861.                 break;
  862.                 
  863.             case mFile:
  864.                 if( menuItem == iQuit )
  865.                     ExitApplication( window );
  866.                 break;
  867.             
  868.             case mEdit:
  869.                 SystemEdit(menuItem-1); 
  870.                 break;
  871.                 
  872.             case mPoints:
  873.                 CheckItem( GetMHandle(mPoints), gcount + 1, false );
  874.                 CheckItem( GetMHandle(mPoints), menuItem, true );
  875.                 gcount = menuItem - 1;
  876.                 InvalRect(&window->portRect);
  877.                 break;
  878.                 
  879.             case mError:
  880.                 {
  881.                     if( menuItem != geindx )
  882.                         {
  883.                             CheckItem( GetMHandle(mError), geindx, false );
  884.                             CheckItem( GetMHandle(mError), menuItem, true );
  885.                             geindx = menuItem;
  886.                             InvalRect(&window->portRect);
  887.                             
  888.                             switch( menuItem )
  889.                                 {
  890.                                     case iOneTenth:
  891.                                         gerror = 0.01;
  892.                                         break;
  893.                                     case iOneQuater:
  894.                                         gerror = 0.25;
  895.                                         break;
  896.                                     case iOneHalf:
  897.                                         gerror = 0.5;
  898.                                         break;
  899.                                     case iThreeQuaters:
  900.                                         gerror = 0.75;
  901.                                         break;
  902.                                     case iOne:
  903.                                         gerror = 1.0;
  904.                                         break;
  905.                                     case iTwo:
  906.                                         gerror = 2.0;
  907.                                         break;
  908.                                     case iFour:
  909.                                         gerror = 4.0;
  910.                                         break;
  911.                                     case iEight:
  912.                                         gerror = 8.0;
  913.                                         break;
  914.                             }
  915.                     }
  916.                 }
  917.                 break;
  918.     }
  919.     HiliteMenu(0);                    /* unhighlight what MenuSelect (or MenuKey) hilited */
  920. }
  921.  
  922. #pragma segment Main
  923. void DoCloseWindow(WindowPtr window)
  924. {
  925.     if ( IsDAWindow(window) )
  926.         CloseDeskAcc(((WindowPeek) window)->windowKind);
  927.     else if ( IsAppWindow(window) ) 
  928.         ExitApplication( window );    
  929. }
  930.  
  931. #pragma segment Main
  932. Boolean IsAppWindow(WindowPtr window)
  933. {
  934.     short        windowKind;
  935.     
  936.     if ( window == nil )
  937.         return false;
  938.     else {    /* application windows have windowKinds >= userKind (8) or dialogKind (2) */
  939.         windowKind = ((WindowPeek) window)->windowKind;
  940.         return (windowKind >= userKind) || (windowKind == dialogKind);
  941.     }
  942. }
  943.  
  944. #pragma segment Main
  945. Boolean IsDAWindow(WindowPtr    window)
  946. {
  947.     if ( window == nil )
  948.         return false;
  949.     else    /* DA windows have negative windowKinds */
  950.         return ((WindowPeek) window)->windowKind < 0;
  951. }
  952.  
  953.  
  954. void ExitApplication( WindowPtr window )
  955. {    
  956.     DisposeWindow( window );
  957.     GXExitGraphics();
  958.     GXDisposeGraphicsClient(gClient);
  959.     ExitToShell();
  960. }
  961.  
  962. long CountQuadratics( const cubic *cube )
  963. {
  964.     long            count;
  965.     extended    a, n;
  966.     
  967.     extended ax;
  968.     extended ay;
  969.     
  970.     ax = Fix2X( - cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x );
  971.     ay = Fix2X( - cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y );
  972.     
  973.     a = hypot( ax, ay );
  974.     
  975.     n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
  976.  
  977.     count = ceil( n );
  978.  
  979.     if( count <= 0 ) 
  980.         count += 1;
  981.  
  982.     return( count );
  983. }
  984.